package html

import (
	"net/http"
	"os"
	"path"
	"strings"
	"yunj/pkg/yunj/util"

	"github.com/flosch/pongo2/v6"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/render"
)

// 自定义固定模板加载标签的节点结构体
type IncludeFixedNode struct {
	FixedFilename string // 固定的模板文件路径
}

// Execute 执行自定义固定模板加载标签的逻辑
func (node *IncludeFixedNode) Execute(ctx *pongo2.ExecutionContext, writer pongo2.TemplateWriter) *pongo2.Error {
	// 加载模板文件
	tpl, err := pongo2.FromFile(node.FixedFilename)
	if err != nil {
		return &pongo2.Error{
			OrigError: err,
		}
	}
	// 执行模板渲染
	err = tpl.ExecuteWriter(ctx.Public, writer)
	if err != nil {
		return &pongo2.Error{
			OrigError: err,
		}
	}
	return nil
}

type PongoRender struct {
	TmplDirs []string
}

func NewRender(tmplDir ...string) *PongoRender {
	p := &PongoRender{
		TmplDirs: tmplDir,
	}
	// 注册自定义标签
	// 包含init.html
	pongo2.RegisterTag("include_yunj_init", func(doc *pongo2.Parser, start *pongo2.Token, arguments *pongo2.Parser) (pongo2.INodeTag, *pongo2.Error) {
		return &IncludeFixedNode{
			FixedFilename: p.FullFilename("/admin/init.html"),
		}, nil
	})

	// 注册自定义过滤器
	// 将 Go 对象转换为 JSON 字节
	pongo2.RegisterFilter("tojson", func(in *pongo2.Value, param *pongo2.Value) (out *pongo2.Value, err *pongo2.Error) {
		inJson, toJsonErr := util.ToJson(in.Interface())
		if toJsonErr != nil {
			err = &pongo2.Error{
				Sender:    "filter:tojson",
				OrigError: toJsonErr,
			}
		} else {
			out = pongo2.AsValue(inJson)
		}
		return
	})

	return p
}

// 完整文件名
func (p *PongoRender) FullFilename(name string) (filename string) {
	for _, tmplDir := range p.TmplDirs {
		if strings.HasPrefix(name, tmplDir) {
			filename = name
			return
		}
		filename = path.Join(tmplDir, name)
		// fmt.Println("尝试模板地址：", fileName, name)
		_, err := os.Stat(filename)
		if !os.IsNotExist(err) {
			return
		}
		filename = ""
	}
	return
}

func (p *PongoRender) Instance(name string, data interface{}) render.Render {
	filename := p.FullFilename(name)
	// fmt.Println("模板地址：", filename, name)

	var template *pongo2.Template
	if gin.Mode() == gin.DebugMode {
		template = pongo2.Must(pongo2.FromFile(filename))
	} else {
		template = pongo2.Must(pongo2.FromCache(filename))
	}

	return &PongoHTML{
		Template: template,
		Name:     name,
		Data:     data.(pongo2.Context),
	}
}

type PongoHTML struct {
	Template *pongo2.Template
	Name     string
	Data     pongo2.Context
}

func (p *PongoHTML) Render(w http.ResponseWriter) error {
	p.WriteContentType(w)
	return p.Template.ExecuteWriter(p.Data, w)
}

func (p *PongoHTML) WriteContentType(w http.ResponseWriter) {
	header := w.Header()
	if val := header["Content-Type"]; len(val) == 0 {
		header["Content-Type"] = []string{"text/html; charset=utf-8"}
	}
}
